<!DOCTYPE html>
<html lang="en">

<head>
    <title>three.js</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <style>
        body {
            background-color: #ffffff;
            margin: 0px;
            overflow: hidden;
        }

        .spinner {
            margin: 430px auto 600px  auto;
            width: 100px;
            height: 100px;
            position: relative;
        }

        .container1 > div, .container2 > div, .container3 > div {
            width: 25px;
            height: 25px;
            background-color: #8253ff;
            border-radius: 100%;
            position: absolute;
            -webkit-animation: bouncedelay 1.2s infinite ease-in-out;
            animation: bouncedelay 1.2s infinite ease-in-out;
            -webkit-animation-fill-mode: both;
            animation-fill-mode: both;
        }

        .spinner .spinner-container {
            position: absolute;
            width: 100%;
            height: 100%;
        }

        .container2 {
            -webkit-transform: rotateZ(45deg);
            transform: rotateZ(45deg);
        }

        .container3 {
            -webkit-transform: rotateZ(90deg);
            transform: rotateZ(90deg);
        }

        .circle1 {
            top: 0;
            left: 0;
        }

        .circle2 {
            top: 0;
            right: 0;
        }

        .circle3 {
            right: 0;
            bottom: 0;
        }

        .circle4 {
            left: 0;
            bottom: 0;
        }

        .container2 .circle1 {
            -webkit-animation-delay: -1.1s;
            animation-delay: -1.1s;
        }

        .container3 .circle1 {
            -webkit-animation-delay: -1.0s;
            animation-delay: -1.0s;
        }

        .container1 .circle2 {
            -webkit-animation-delay: -0.9s;
            animation-delay: -0.9s;
        }

        .container2 .circle2 {
            -webkit-animation-delay: -0.8s;
            animation-delay: -0.8s;
        }

        .container3 .circle2 {
            -webkit-animation-delay: -0.7s;
            animation-delay: -0.7s;
        }

        .container1 .circle3 {
            -webkit-animation-delay: -0.6s;
            animation-delay: -0.6s;
        }

        .container2 .circle3 {
            -webkit-animation-delay: -0.5s;
            animation-delay: -0.5s;
        }

        .container3 .circle3 {
            -webkit-animation-delay: -0.4s;
            animation-delay: -0.4s;
        }

        .container1 .circle4 {
            -webkit-animation-delay: -0.3s;
            animation-delay: -0.3s;
        }

        .container2 .circle4 {
            -webkit-animation-delay: -0.2s;
            animation-delay: -0.2s;
        }

        .container3 .circle4 {
            -webkit-animation-delay: -0.1s;
            animation-delay: -0.1s;
        }

        @-webkit-keyframes bouncedelay {
            0%, 80%, 100% {
                -webkit-transform: scale(0.0)
            }
            40% {
                -webkit-transform: scale(1.0)
            }
        }

        @keyframes bouncedelay {
            0%, 80%, 100% {
                transform: scale(0.0);
                -webkit-transform: scale(0.0);
            }
            40% {
                transform: scale(1.0);
                -webkit-transform: scale(1.0);
            }
        }
    </style>
</head>

<body>
<div class="spinner">
    <div class="spinner-container container1">
        <div class="circle1"></div>
        <div class="circle2"></div>
        <div class="circle3"></div>
        <div class="circle4"></div>
    </div>
    <div class="spinner-container container2">
        <div class="circle1"></div>
        <div class="circle2"></div>
        <div class="circle3"></div>
        <div class="circle4"></div>
    </div>
    <div class="spinner-container container3">
        <div class="circle1"></div>
        <div class="circle2"></div>
        <div class="circle3"></div>
        <div class="circle4"></div>
    </div>
</div>
<script src="js/md5.js"></script>
<script src="js/three.js"></script>
<script src="js/controls/TrackballControls.js"></script>
<script src="js/libs/stats.min.js"></script>
<script src="../static/jquery-3.0.0.min.js"></script>
<script>
    var container, controls, stats, texLoader, map, myfont;

    var camera, scene, renderer, annie = [];

    var cloud, cloud2, bird, fox = [],
        text = [],
        circle = [],
        headPortrait = [],
        headPortraitMd5 = [];

    var items = {};

    var start = Date.now(),
        clock = new THREE.Clock();

    var cWidth = window.innerWidth;
    var cHeight = window.innerHeight;
    var cloudx = 0,
        count = 0,
        foxOffsize = -485,
        openSec = 0,
        seconds = 0,
        fail = 0;

    var matLite = new THREE.MeshBasicMaterial({
        color: 0x333333,
        side: THREE.DoubleSide,
        transparent: true
    });

    init();

    function init() {

        container = document.createElement('div');
        container.style.width = cWidth + 'px';
        container.style.height = cHeight + 'px';
        container.style.margin = 'auto';
        container.className = "treejs";
        container.style.background = "#f0f0f0";
        document.body.appendChild(container);

        camera = new THREE.PerspectiveCamera(45, cWidth / cHeight, 0.1, 60000);
        camera.position.z = 880;

        scene = new THREE.Scene();
        scene.background = new THREE.Color(0xf0f0f0);

        // scene.add(new THREE.GridHelper(1000, 10));

        // var axesHelper = new THREE.AxesHelper(500);
        // scene.add(axesHelper);

        // bg
        texLoader = new THREE.TextureLoader();
        map = texLoader.load('images/bg.png');
        var bg = new THREE.Sprite(new THREE.SpriteMaterial({
            map: map,
            transparent: true
        }));
        bg.scale.set(1300, 732, 1);
        bg.position.set(0, 0, 0);
        scene.add(bg);

        // cloud1
        texLoader = new THREE.TextureLoader();
        map = texLoader.load('images/cloud.png');
        cloud = new THREE.Sprite(new THREE.SpriteMaterial({
            map: map,
            transparent: true
        }));
        cloud.scale.set(1288, 108, 1);
        cloud.position.set(0, 290, 1);
        scene.add(cloud);

        // cloud2
        texLoader = new THREE.TextureLoader();
        map = texLoader.load('images/cloud.png');
        cloud2 = new THREE.Sprite(new THREE.SpriteMaterial({
            map: map,
            transparent: true
        }));
        cloud2.scale.set(1288, 108, 1);
        cloud2.position.set(0, 290, 1);
        scene.add(cloud2);

        // bird
        texLoader = new THREE.TextureLoader();
        map = texLoader.load('images/bird.png');
        bird = new THREE.Sprite(new THREE.SpriteMaterial({
            map: map,
            transparent: true
        }));
        bird.scale.set(659, 158, 1);
        bird.position.set(0, 350, 2);
        scene.add(bird);

        // tree
        texLoader = new THREE.TextureLoader();
        map = texLoader.load('images/tree.png');
        var tree = new THREE.Sprite(new THREE.SpriteMaterial({
            map: map,
            transparent: true
        }));
        tree.scale.set(1300 - 125, 732 - 125, 1);
        tree.position.set(0, 0, 85);
        scene.add(tree);

        renderer = new THREE.WebGLRenderer({
            alpha: false
        });

        renderer.setPixelRatio(window.devicePixelRatio);

        renderer.setSize(cWidth, cHeight);

        container.appendChild(renderer.domElement);

        controls = new THREE.TrackballControls(camera);

        // stats = new Stats();
        // container.appendChild(stats.dom);

        setInterval(() => {
            openSec = 1;
            seconds++;
        }, 1000);

        render();

        var loader = new THREE.FontLoader();
        loader.load('fonts/STZhongsong_Regular.json', function (font) {
            myfont = font;
            $(".spinner").hide();
            animate();
        }); //end load function

        window.addEventListener('resize', onWindowResize, false);
    }

    function animate() {

        requestAnimationFrame(animate);
        render();
        renderer.render(scene, camera);
        // controls.update();
        // stats.update();
    }

    function createText(i) {
        var message = items[i].nickName.substr(0, 6);
        if (text[i]) {
            if (text[i].message == message) return;
            scene.remove(text[i]);
        }
        console.log('创建文字：' + message);
        var geometry_text = new THREE.ShapeBufferGeometry(myfont.generateShapes(message, 15));
        geometry_text.computeBoundingBox();
        text[i] = new THREE.Mesh(geometry_text, matLite);
        text[i].message = message;
        if (message.gblen() > 8) {
            text[i].position.set(-65 + foxOffsize + i * 108.5, 0, 90);
        } else if (message.gblen() > 6) {
            text[i].position.set(-40 + foxOffsize + i * 108.5, 0, 90);
        } else if (message.gblen() > 4) {
            text[i].position.set(-30 + foxOffsize + i * 108.5, 0, 90);
        } else {
            text[i].position.set(-22 + foxOffsize + i * 108.5, 0, 90);
        }
        scene.add(text[i]);
    }

    function createHeadPortrait(i) {
        if (circle[i]) {
            if (circle[i].avatarUrl != items[i].avatarUrl) {
                var material = new THREE.MeshBasicMaterial({
                    map: addheadPortrait(items[i].avatarUrl),
                    transparent: true,
                    side: THREE.DoubleSide
                });
                circle[i].material = material;
                circle[i].avatarUrl = items[i].avatarUrl;
                console.log('替换头像：' + items[i].avatarUrl);
                return;
            }
        } else {
            console.log('创建头像：' + items[i].avatarUrl);
            var geometry_headPortrait = new THREE.CircleBufferGeometry(32, 360);
            var material_headPortrait = new THREE.MeshBasicMaterial({
                map: addheadPortrait(items[i].avatarUrl),
                transparent: true,
                side: THREE.DoubleSide
            });
            circle[i] = new THREE.Mesh(geometry_headPortrait, material_headPortrait);
            circle[i].position.set(foxOffsize + i * 108.5, 0, 90);
            circle[i].avatarUrl = items[i].avatarUrl;
            scene.add(circle[i]);
        }
    }

    function createFox(i) {
        var texLoader = new THREE.TextureLoader();
        var map = texLoader.load('images/fox.png');
        annie[i] = new TextureAnimator(map, 2, 1, 2, 200);
        var runnerMaterial = new THREE.MeshBasicMaterial({
            map: map,
            transparent: true,
            side: THREE.DoubleSide
        });
        var runnerGeometry = new THREE.PlaneGeometry(94, 111, 1, 1);
        fox[i] = new THREE.Mesh(runnerGeometry, runnerMaterial);
        fox[i].position.set(foxOffsize + i * 108.5, 0, 90);
        scene.add(fox[i]);
    }

    function render() {

        var timer = Date.now() - start;

        count++;
        cloudx = cloudx + 0.1;
        if (cloudx > 844) cloudx = 0;
        cloud.position.x = cloudx;
        cloud.position.z = 50 + Math.sin(timer * 0.0005) * 20;
        cloud2.position.x = cloudx - cWidth;
        cloud2.position.z = 50 + Math.sin(timer * 0.0005) * 30;

        bird.position.x = Math.sin(timer * 0.0010) * 150;
        bird.position.y = Math.sin(timer * 0.0015) * 30 * -1;

        if (seconds === 1 && openSec === 1) {
            openSec = 0;
            $.ajax({
                url: "/wechat/Climbtree/list/#?limit=2",
                type: "POST",
                dataType: "json",
                async: true,
                timeout: 1000,
                success: function (data) {
                    items = data.items;
                    if (items.length > 0) {
                        fail = 0;
                        for (var i = 0; i < items.length; i++) {

                            // headPortrait
                            createHeadPortrait(i);

                            // text
                            createText(i);

                            // fox
                            createFox(i);

                            circle[i].position.y = 110 - 300 + items[i].times;
                            text[i].position.y = 60 - 300 + items[i].times;
                            fox[i].position.y = -300 + items[i].times;
                        }
                    } else {
                        fail++;
                    }
                },
                complete: function () {
                    fail++;
                }
            });
        }

        if (seconds >= 1) {
            var delta = clock.getDelta();
            for (var i = 0; i < items.length; i++) {
                annie[i].update(1000 * delta);
            }
        }

        if (seconds % 3 === 0 && openSec === 1) {
            openSec = 0;
            $.ajax({
                url: "/wechat/Climbtree/list/",
                type: "POST",
                dataType: "json",
                async: true,
                timeout: 1000,
                success: function (data) {
                    items = data.items;
                    if (items.length > 0) {
                        fail = 0;
                        for (var i = 0; i < items.length; i++) {
                            if (typeof fox[i] === "undefined") { // 新增

                                // headPortrait
                                createHeadPortrait(i);

                                // text
                                createText(i);

                                // fox
                                createFox(i);

                            } else {

                                // headPortrait
                                createHeadPortrait(i);

                                // text
                                createText(i);

                            }
                            circle[i].position.y = 110 - 300 + items[i].times;
                            text[i].position.y = 60 - 300 + items[i].times;
                            fox[i].position.y = -300 + items[i].times;
                        }
                    } else {
                        fail++;
                    }
                },
                complete: function () {
                    fail++;
                }
            });
        }
    }

    function onWindowResize() {

        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);

    }

    function TextureAnimator(texture, tilesHoriz, tilesVert, numTiles, tileDispDuration) {

        // note: texture passed by reference, will be updated by the update function.
        this.tilesHorizontal = tilesHoriz;
        this.tilesVertical = tilesVert;
        // how many images does this spritesheet contain?
        //  usually equals tilesHoriz * tilesVert, but not necessarily,
        //  if there at blank tiles at the bottom of the spritesheet.
        this.numberOfTiles = numTiles;
        texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
        texture.repeat.set(1 / this.tilesHorizontal, 1 / this.tilesVertical);

        // how long should each image be displayed?
        this.tileDisplayDuration = tileDispDuration;

        // how long has the current image been displayed?
        this.currentDisplayTime = 0;

        // which image is currently being displayed?
        this.currentTile = 0;

        this.update = function (milliSec) {
            this.currentDisplayTime += milliSec;
            while (this.currentDisplayTime > this.tileDisplayDuration) {
                this.currentDisplayTime -= this.tileDisplayDuration;
                this.currentTile++;
                if (this.currentTile == this.numberOfTiles)
                    this.currentTile = 0;
                var currentColumn = this.currentTile % this.tilesHorizontal;
                texture.offset.x = currentColumn / this.tilesHorizontal;
                var currentRow = Math.floor(this.currentTile / this.tilesHorizontal);
                texture.offset.y = currentRow / this.tilesVertical;
            }
        };

    }

    function addheadPortrait(url) {
        var md5str = hex_md5(url);
        if (typeof headPortrait[md5str] === "undefined") {
            var texLoaders = new THREE.TextureLoader();
            var maps = texLoaders.load(url);
            headPortrait[md5str] = maps;
            headPortraitMd5.push(md5str);
            return headPortrait[md5str];
        } else {
            return headPortrait[md5str];
        }
    }

    String.prototype.gblen = function () {
        var len = 0;
        for (var i = 0; i < this.length; i++) {
            if (this.charCodeAt(i) > 127 || this.charCodeAt(i) == 94) {
                len += 2;
            } else {
                len++;
            }
        }
        return len;
    }
</script>

</body>

</html>